#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/types.h>

#define NUM 1024
#define SIZE 32
#define SEP " "//分隔符（必须字符串）
//保存完整的命令行字符串
char cmd_line[NUM];
//保存打散之后的命令行字符串
char *g_argv[SIZE];

//shell运行原理：通过让子进程执行命令，父进程等待&解析命令
int main()
{
    //0.命令行解释器一定是一个常驻内存的进程，不退出
    while(1)
    {
        //1.打印出提示信息[hbr@localhost myshell]#
        printf("[root@localhost myshell]#");
        fflush(stdout);
        memset(cmd_line,'\0',sizeof cmd_line);
        //2.获取用户的键盘输入[输入的是各种指令和选项："ls -a -l"]
        if(fgets(cmd_line,sizeof cmd_line,stdin)==NULL)
        {
            continue;
        }
        //处理输入后的回车键导致的换行问题
        cmd_line[strlen(cmd_line)-1]='\0';
        printf("echo: %s\n",cmd_line);
        //3.命令行解析 "ls -a -l" -> "ls" "-a" "-l"
        g_argv[0]=strtok(cmd_line,SEP);//第一次调用，传入原始字符串
        int index=1;
        while(g_argv[index++]=strtok(NULL,SEP));//第二次还要解析原始字符串，传入NULL
       
        // for debug 
       // for(index=0;g_argv[index];index++)
       // {
       //     printf("g_argv[%d]: %s\n",index,g_argv[index]);
       // }
        
       //4.TODO内置命令,让父进程（shell）自己执行的命令叫做内置命令、内建命令
        //cd命令不能在子进程运行
        if(strcmp(g_argv[0],"cd")==0)
        {
            if(g_argv[1]!=NULL) chdir(g_argv[1]);
            continue;
        }
        //5.fork()
        pid_t id=fork();
        if(id==0)
        {
            printf("下面功能让子进程进行的\n");
            execvp(g_argv[0],g_argv);
            exit(1);
        }
        int status=0;
        pid_t ret=waitpid(id,&status,0);
        if(ret>0) printf("exit code:%d\n",WEXITSTATUS(status));
    }
    return 0;
}
